import type { ExecutorConfig } from '../index'
import type { RequestConfig, RequestResponse } from './request_handler'
import { logger } from '../../../types/constants'
import { SYMBOLS } from '../../../types/interfaces'
import { ToolKit } from '../../utils/toolkit'
import { RequestHandler } from './request_handler'
import { RequestInterval } from './request_interval'

export interface RequestQueueItem {
  url: string
  resolve: (value: any) => void
  reject: (error: any) => void
  config: RequestConfig & ExecutorConfig
  requestId: number
  timestamp: number
}

export interface RequestStatus {
  status: 'active' | 'queued' | 'not_found'
  url?: string
  position?: number
  duration?: number
}

export interface RequestStatusItem {
  requestId: number
  url: string
  position?: number
  duration?: number
  waitTime?: number
}

export interface RequestStatusMap {
  active: RequestStatusItem[]
  queued: RequestStatusItem[]
  stats: {
    active: number
    queued: number
    processing: string[]
    maxConcurrent: number
  }
}

export interface RequestSchedulerQueue {
  queueLength: number
  activeCount: number
  processing: string[]
  maxConcurrent: number
}

/**
 * 智能请求调度器：管理并发请求和频率限制
 */
export class RequestScheduler {
  private readonly name: string = 'RequestScheduler'
  private static instance: RequestScheduler
  private readonly requestHandler: RequestHandler = RequestHandler.getInstance()
  private readonly intervalManager: RequestInterval = RequestInterval.getInstance()
  private readonly MAX_CONCURRENT = 3
  private activeCount = 0
  private queue: RequestQueueItem[] = []
  private processing: Set<string> = new Set()
  private activeRequests: Map<number, { // 跟踪活跃请求
    abort: () => void
    url: string
    timestamp: number
  }> = new Map()

  static getInstance(): RequestScheduler {
    if (!RequestScheduler.instance) {
      RequestScheduler.instance = new RequestScheduler()
    }
    return RequestScheduler.instance
  }

  /**
   * 生成唯一的整数请求 ID
   */
  private generateRequestId(): number {
    const timestamp = Date.now() % 1000000000 // 限制长度
    const random = Math.floor(Math.random() * 10000) // 4 位随机数
    return timestamp * 10000 + random
  }

  /**
   * 调度请求
   */
  async scheduleRequest<T = any>(
    url: string,
    config: RequestConfig & ExecutorConfig,
  ): Promise<RequestResponse<T>> {
    return new Promise((resolve, reject) => {
      const requestId = this.generateRequestId()
      const queueItem: RequestQueueItem = {
        url,
        resolve: resolve as (value: any) => void,
        reject,
        config,
        requestId,
        timestamp: Date.now(),
      }

      this.queue.push(queueItem)
      this.processQueue()
    })
  }

  /**
   * 处理队列
   */
  private async processQueue(): Promise<void> {
    // 检查并发限制
    if (this.activeCount >= this.MAX_CONCURRENT)
      return

    // 检查队列是否为空
    if (this.queue.length === 0)
      return

    // 按优先级、时间排序来处理请求
    this.queue.sort((a, b) => {
      // 1）先按优先级排序（数字越大，优先级越高）
      const priorityDiff = (b.config.priority || 0) - (a.config.priority || 0)

      if (priorityDiff !== 0)
        return priorityDiff

      // 2）优先级相同，按时间排序（越早请求越先处理）
      return a.timestamp - b.timestamp
    })

    for (let i = 0; i < this.queue.length; i++) {
      if (this.activeCount >= this.MAX_CONCURRENT)
        break

      const item = this.queue[i]

      // 检查请求间隔
      const intervalCheck = this.intervalManager.canRequest(item.url)

      if (!intervalCheck.canRequest)
        continue // 跳过还未到间隔时间的请求

      // 从队列中移除
      this.queue.splice(i, 1)
      i--

      // 处理请求
      await this.processRequest(item)
    }
  }

  /**
   * 处理单个请求
   */
  private async processRequest(item: RequestQueueItem): Promise<void> {
    this.activeCount++
    this.processing.add(item.url)

    // 创建取消控制器
    const abortController = new AbortController()
    const abort = () => abortController.abort()

    // 记录活跃请求
    const requestRecord = {
      abort,
      url: item.url,
      timestamp: Date.now(),
    }
    this.activeRequests.set(item.requestId, requestRecord)

    try {
      // 记录请求开始
      this.intervalManager.recordRequestStart(item.url, item.config)

      const result = await this.requestHandler.request(item.url, {
        ...item.config,
        signal: abortController.signal, // 传递取消信号
        requestId: item.requestId,
      })

      // 记录请求结果
      if (result.status === 'success') {
        this.intervalManager.recordRequestSuccess(item.url, item.config, result.data)
      }
      else {
        this.intervalManager.recordRequestError(item.url, result.error)
      }

      item.resolve(result)
    }
    catch (error: any) {
      if (ToolKit.error.isAbortError(error)) {
        item.reject(ToolKit.error.createAbortError(`请求已被取消: #${item.requestId}`))
      }
      else {
        item.reject(error)
      }
    }
    finally {
      // 清理活跃请求记录
      this.activeRequests.delete(item.requestId)
      this.activeCount--
      this.processing.delete(item.url)

      // 继续处理队列
      setTimeout(() => this.processQueue(), 0)
    }
  }

  /**
   * 取消指定请求
   */
  cancelRequest(requestId: number): boolean {
    const request = this.activeRequests.get(requestId)

    if (request) {
      try {
        request.abort() // 调用取消函数
        this.activeRequests.delete(requestId)
        this.activeCount--
        this.processing.delete(request.url)

        logger.info(`[${this.name}] ${SYMBOLS.OTHERS.STOP} 取消请求 #${requestId}`, {
          url: request.url,
          duration: Date.now() - request.timestamp,
        })
        return true
      }
      catch (error) {
        logger.error(`[${this.name}] 取消请求失败`, { requestId, error })
        return false
      }
    }

    // 检查是否在队列中
    const queueIndex = this.queue.findIndex(item => item.requestId === requestId)
    if (queueIndex !== -1) {
      const queueItem = this.queue[queueIndex]
      this.queue.splice(queueIndex, 1)
      queueItem.reject(ToolKit.error.createAbortError('请求已被取消'))

      logger.info(`[${this.name}] ${SYMBOLS.OTHERS.STOP} 取消队列中的请求 #${requestId}`, {
        url: queueItem.url,
      })
      return true
    }

    logger.debug(`[${this.name}] 未找到要取消的请求 #${requestId}`)
    return false
  }

  /**
   * 取消指定 URL 的所有请求
   */
  cancelRequestsByUrl(url: string): number {
    let cancelledCount = 0

    // 取消活跃请求
    this.activeRequests.forEach((request, requestId) => {
      if (request.url === url) {
        if (this.cancelRequest(requestId)) {
          cancelledCount++
        }
      }
    })

    // 取消队列中的请求
    const remainingQueue: RequestQueueItem[] = []
    this.queue.forEach((item) => {
      if (item.url === url) {
        item.reject(ToolKit.error.createAbortError(`URL 请求已被取消: ${url}`))
        cancelledCount++
      }
      else {
        remainingQueue.push(item)
      }
    })
    this.queue = remainingQueue

    if (cancelledCount > 0) {
      logger.info(`[${this.name}] ${SYMBOLS.OTHERS.STOP} 取消 URL 的所有请求`, {
        url,
        cancelledCount,
      })
    }

    return cancelledCount
  }

  /**
   * 取消所有请求
   */
  cancelAllRequests(): number {
    const totalCount = this.activeRequests.size + this.queue.length

    // 取消所有活跃请求
    this.activeRequests.forEach((_, requestId) => {
      this.cancelRequest(requestId)
    })

    // 取消所有队列请求
    this.queue.forEach((item) => {
      item.reject(ToolKit.error.createAbortError('所有请求已被取消'))
    })
    this.queue = []
    this.activeCount = 0
    this.processing.clear()

    logger.info(`[${this.name}] ${SYMBOLS.OTHERS.STOP} 取消所有请求`, {
      totalCancelled: totalCount,
    })

    return totalCount
  }

  /**
   * 获取请求状态
   */
  getRequestStatus(requestId: number): RequestStatus {
    if (this.activeRequests.has(requestId)) {
      return { status: 'active', url: this.activeRequests.get(requestId)!.url }
    }

    const inQueue = this.queue.some(item => item.requestId === requestId)
    if (inQueue) {
      const queueItem = this.queue.find(item => item.requestId === requestId)!
      return { status: 'queued', url: queueItem.url, position: this.queue.indexOf(queueItem) + 1 }
    }

    return { status: 'not_found' }
  }

  /**
   * 获取所有请求状态
   */
  getAllRequestsStatus(): RequestStatusMap {
    return {
      active: Array.from(this.activeRequests.entries()).map(([requestId, record]) => ({
        requestId,
        url: record.url,
        duration: Date.now() - record.timestamp,
      })),
      queued: this.queue.map((item, index) => ({
        requestId: item.requestId,
        url: item.url,
        position: index + 1,
        waitTime: Date.now() - item.timestamp,
      })),
      stats: {
        active: this.activeCount,
        queued: this.queue.length,
        processing: Array.from(this.processing),
        maxConcurrent: this.MAX_CONCURRENT,
      },
    }
  }

  /**
   * 获取队列状态
   */
  getQueueStatus(): RequestSchedulerQueue {
    return {
      queueLength: this.queue.length,
      activeCount: this.activeCount,
      processing: Array.from(this.processing),
      maxConcurrent: this.MAX_CONCURRENT,
    }
  }

  /**
   * 清空队列
   */
  clearQueue(): void {
    this.queue.forEach((item) => {
      item.reject(new Error('请求队列已清空'))
    })
    this.queue = []
  }
}
